﻿using System;
using BGShell.PowerShell.Runspaces;

namespace BGShell.PowerShell.Controls
{
    partial class ConsoleControl
    {
        private sealed class CommandHistory
        {
            private readonly ConsoleControl _ctl;
            private readonly InputReader _reader;

            private String[] _history;
            private Int32? _index;
            private String _line;

            private BGShellPipelineProxy _pipeline;
            private Action _callback;

            public CommandHistory(ConsoleControl ctl, InputReader reader)
            {
                _ctl = ctl;
                _reader = reader;
            }

            public void Prev()
            {
                BeginLoadHistory(SelectPrev);
            }

            public void Next()
            {
                BeginLoadHistory(SelectNext);
            }

            public void UpdateEditedLine()
            {
                _index = null;
                _callback = null;

                if (_pipeline != null)
                {
                    _pipeline.StopAsync();
                    _pipeline = null;
                }
            }

            private void GotHistory(String[] history)
            {
                _ctl.BeginInvokeIfRequired(GotHistoryUnsafe, history);
            }

            private void GotHistoryUnsafe(String[] history)
            {
                var callback = _callback;

                _callback = null;
                _pipeline = null;
                _history = history;
                _index = history.Length;

                if (callback != null)
                {
                    callback();
                }
            }

            private void SelectPrev()
            {
                if (_index == 0)
                {
                    return;
                }
                else
                {
                    _index -= 1;
                }

                if (_index < _history.Length)
                {
                    _reader.Text = _history[_index.Value];
                }
            }

            private void SelectNext()
            {
                if (_index.Value < (_history.Length - 1))
                {
                    _index += 1;
                    _reader.Text = _history[_index.Value];
                }
                else if (_index != _history.Length)
                {
                    _index = null;
                    _reader.Text = _line;
                }
            }

            private void BeginLoadHistory(Action callback)
            {
                if (_index.HasValue)
                {
                    callback();
                }
                else
                {
                    _line = _reader.Text;
                    _callback = callback;
                    _pipeline = _ctl.Runspace.BeginGetHistory(GotHistory);
                }
            }
        }
    }
}
